package com.iot08.api.service.supplement;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.iot08.api.constant.Constant;
import com.iot08.api.service.AccountService;
import com.iot08.api.service.DeviceLocationService;
import com.iot08.api.service.DeviceService;
import com.iot08.api.service.WxgzConfigService;
import com.iot08.api.utils.CXUtil;
import com.iot08.api.vo.request.*;
import com.iot08.common.entity.app.Account;
import com.iot08.common.entity.app.Device;
import com.iot08.common.entity.app.Wxgzconfig;
import com.iot08.common.utils.CollectionUtil;
import com.iot08.common.utils.HttpReq;
import com.iot08.common.utils.StringUtil;
import com.iot08.common.utils.response.ResponseMap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @version 1.0
 * @Description:
 * @time: 2021/5/8 10:37
 * @author: Rock
 */
@Slf4j
@Service
public class WxWebApiService {

    @Resource
    private WxgzConfigService wxgzConfigService;
    @Resource
    private AccountService accountService;
    @Resource
    private DeviceService deviceService;
    @Resource
    private DeviceLocationService deviceLocationService;
    @Resource
    private WeixinService weixinService;

    @Value("${wxgz.appId}")
    private String wxgzAppId;
    @Value("${wxgz.appSecret}")
    private String wxgzAppSecret;

    /**
     * @param code
     * @param appid
     * @param appsecret
     * @time: 2021/5/8 14:17
     * @author: Rock
     * @version 1.0
     */
    private String getAccessToken(String code, String appid, String appsecret) {
        StringBuilder url = new StringBuilder("https://api.weixin.qq.com/sns/oauth2/access_token?grant_type=authorization_code");
        url.append("&appid=").append(appid).append("&secret=").append(appsecret).append("&code=").append(code);
        String res = HttpReq.sendGet(url.toString());
        if (StringUtil.isNotBlank(res)) {
            try {
                JSONObject resJson = JSONObject.parseObject(res);
                if (resJson != null && StringUtil.isNotBlank(resJson.get("openid"))) {
                    return resJson.getString("openid");
                }
            } catch (Exception e) {
                log.error("getAccessToken is Exception. url={}.  res={}. exception={}", url, res, e.getMessage());
            }
        }
        return "";
    }

    /**
     * 根据code 获取的微信用户在我们系统中的信息
     *
     * @param vo
     * @time: 2021/5/8 14:17
     * @author: Rock
     * @version 1.0
     */
    public Object getOpenId(WxOauthReqVO vo) {
        Wxgzconfig wxgzconfig = wxgzConfigService.findByAppid(vo.getAppid());
        if (wxgzconfig == null) {
            log.error("getOpenId Wxgzconfig is null. vo={}", vo);
            return "缺少公众号配置";
        }
        String wxid = getAccessToken(vo.getCode(), vo.getAppid(), wxgzconfig.getAppsecret());
        if (StringUtil.isNotBlank(wxid)) {
            Account account = accountService.findOne(new Query(Criteria.where("wxid").is(wxid)));
            if (account != null) {
                JSONObject res = new JSONObject();
                StringBuilder imeis = new StringBuilder();
                StringBuilder names = new StringBuilder();
                if (CollectionUtil.isNotEmpty(account.getDeviceMap())) {
                    List<Device> deviceList = deviceService.listByIds(account.getDeviceMap().keySet());
                    for (Device d : deviceList) {
                        imeis.append(",").append(d.getId());
                        names.append(",").append(d.getName());
                    }
                }
                res.put("imei", imeis);
                res.put("name", names);
                res.put("accountOpenid", account.getId());
                res.put("accessToken", accountService.getAccesstoken(account));
                res.put("chatImei", account.getWxgzChatImei() == null ? "" : account.getWxgzChatImei());
                return res;
            }
        }
        log.error("getOpenId Account is null. vo={}. wxid={}", vo, wxid);
        return "账号不存在";
    }

    /**
     * 定位页面授权调用的接口
     *
     * @param vo
     * @time: 2021/5/8 15:18
     * @author: Rock
     * @version 1.0
     */
    public Object getOpenIdForLocAuth(WxOauthReqVO vo) {
        Wxgzconfig wxgzconfig = wxgzConfigService.findByAppid(vo.getAppid());
        if (wxgzconfig == null) {
            log.error("getOpenIdForLocAuth Wxgzconfig is null. vo={}", vo);
            return "缺少公众号配置";
        }
        String wxid = getAccessToken(vo.getCode(), vo.getAppid(), wxgzconfig.getAppsecret());
        if (StringUtil.isNotBlank(wxid)) {
            Account account = accountService.findOne(new Query(Criteria.where("wxid").is(wxid)));
            if (account != null) {
                JSONObject res = new JSONObject();
                if (StringUtil.isBlank(account.getWxgzChatImei())) {
                    res.put("openid", account.getId());
                    res.put("accessToken", accountService.getAccesstoken(account));
                    res.put("code", 10001);
                    return res;
                }
                Device device = deviceService.findById(account.getWxgzChatImei());
                if (device != null) {
                    res.put("info", deviceLocationService.getLocationLastToJuHuo(account.getWxgzChatImei(), 0));
                    res.put("lastBattery", device.getLastBattery());
                    res.put("openid", wxid);
                    res.put("name", device.getName());
                }
                return res;
            }
        }
        log.error("getOpenIdForLocAuth Account is null. vo={}. wxid={}", vo, wxid);
        return "账号不存在";
    }

    /**
     * 切换设备
     *
     * @param vo
     * @time: 2021/5/8 17:13
     * @author: Rock
     * @version 1.0
     */
    public Object swichDevice(SwichDeviceReqVO vo) {
        JSONObject res = new JSONObject();
        Account account = accountService.findById(vo.getOpenid());
        Device device = deviceService.findById(vo.getImei());
        if (account != null && device != null) {
            Update updateAccount = new Update();
            updateAccount.set("imei", vo.getImei());
            accountService.updateById(vo.getOpenid(), updateAccount);
            String content = String.format("通知：您已切换为%s的设备，将只能给%s发送语音/文字。如需要给其他设备发送语音/文字消息，需到管理页面切换为其他设备。", device.getName(), device.getName());
            boolean send = weixinService.replyWxMsg(Constant.WEIXIN_PUSH_TYPE_1, content, account.getWxgzMasterId(),account.getWxid());
            if (send) {
                res.put("msg", "ok");
            } else {
                res.put("msg", "fail");
            }
            return res;
        }
        log.error("swichDevice Account or Device is null. vo={}", vo);
        res.put("msg", "fail");
        return "fail";
    }

    /**
     * 获取设备最后一次定位的信息
     *
     * @param vo
     * @time: 2021/5/8 17:27
     * @author: Rock
     * @version 1.0
     */
    public Object getLastLocation(OpenidParamReqVO vo) {
        Account account = accountService.findOne(new Query(Criteria.where("wxid").is(vo.getOpenid())));
        if (account != null && StringUtil.isNotBlank(account.getWxgzChatImei())) {
            JSONObject res = new JSONObject();
            Device device = deviceService.findById(account.getWxgzChatImei());
            if (device != null) {
                res.put("info", deviceLocationService.getLocationLastToJuHuo(account.getWxgzChatImei(), 0));
                res.put("lastBattery", device.getLastBattery());
                res.put("name", device.getName());
            }
            return res;
        }
        log.error("getLastLocation Account is null. vo={}", vo);
        return "账号不存在";
    }

    /**
     * 下发设备主动定位
     *
     * @param vo
     * @time: 2021/5/8 17:39
     * @author: Rock
     * @version 1.0
     */
    public Object sendLastLocation(OpenidParamReqVO vo) {
        Account account = accountService.findOne(new Query(Criteria.where("wxid").is(vo.getOpenid())));
        if (account != null && StringUtil.isNotBlank(account.getWxgzChatImei())) {
            JSONObject res = new JSONObject();
            Device device = deviceService.findById(account.getWxgzChatImei());
            if (device != null) {
                res.put("info", deviceLocationService.getNowLocationToJuHuo(account.getWxgzChatImei(), account.getId()));
                res.put("name", device.getName());
            }
            return res;
        }
        log.error("getLastLocation Account is null. vo={}", vo);
        return "账号不存在";
    }

    /**
     * 解绑设备
     *
     * @param vo
     * @time: 2021/5/8 18:29
     * @author: Rock
     * @version 1.0
     */
    public Object unBindDevice(SwichDeviceReqVO vo) {
        JSONObject res = new JSONObject();
        Account account = accountService.findById(vo.getOpenid());
        if (account != null) {
            ImeiParamReqBodyFormVO reqVO = new ImeiParamReqBodyFormVO();
            reqVO.setImei(vo.getImei());
            reqVO.setOpenid(vo.getOpenid());
            reqVO.setAccesstoken(accountService.getAccesstoken(account));
            //解绑设备操作
            accountService.delRelatedDevice(reqVO);
            if (vo.getImei().equals(account.getWxgzChatImei()) && CollectionUtil.isNotEmpty(account.getDeviceMap())) {
                if (account.getDeviceMap().size() == 1) {
                    accountService.updateById(vo.getOpenid(), new Update().unset("wxgz_chat_imei"));
                    String content = "通知：您已解绑设备。";
                    boolean send = weixinService.replyWxMsg(Constant.WEIXIN_PUSH_TYPE_1, content, account.getWxgzMasterId(), account.getWxid());
                    res.put("msg", "notdevice");
                    return res;
                }
                for (String key : account.getDeviceMap().keySet()) {
                    if (!key.equals(vo.getImei())) {
                        Device device = deviceService.findById(key);
                        accountService.updateById(vo.getOpenid(), new Update().set("wxgz_chat_imei", key));
                        String content = String.format("通知：您已解绑设备%s。系统已为您切换为%s的设备", vo.getImei(), device.getName());
                        boolean send = weixinService.replyWxMsg(Constant.WEIXIN_PUSH_TYPE_1, content, account.getWxgzMasterId(), account.getWxid());
                        break;
                    }
                }
            }
            res.put("msg", "ok");
        }
        log.error("unBindDevice Account is null. vo={}", vo);
        res.put("msg", "账号不存在");
        return res;
    }

    /**
     * 绑定设备
     *
     * @param vo
     * @time: 2021/5/8 18:58
     * @author: Rock
     * @version 1.0
     */
    public Object bindDevice(BindDeviceReqVO vo) throws IOException {
        Device device = deviceService.findById(vo.getImei());
        if (device == null) {
            return "2001";
        }
        Account account = accountService.findById(vo.getOpenid());
        if (account != null) {
            AddRelatedDeviceReqBodyFormVO reqVO = new AddRelatedDeviceReqBodyFormVO();
            reqVO.setOpenid(vo.getOpenid());
            reqVO.setAccesstoken(vo.getAccesstoken());
            reqVO.setPhone(vo.getPhone());
            reqVO.setRelationship_image_id(vo.getRelationship_image_id());
//            reqVO.setAuthcode(vo.getAuthcode());
            reqVO.setImei(vo.getImei());
            reqVO.setName(StringUtil.isNotBlank(device.getName()) ? device.getName() : vo.getName());
            reqVO.setRelationship(weixinService.getWxUserName(account.getWxid(), account.getWxgzMasterId()));
            ResponseMap responseMap = accountService.addRelatedDevice(reqVO, null, true);
            return responseMap.get("code");
        }
        log.error("unBindDevice Account is null. vo={}", vo);
        return "账号不存在";
    }

    /**
     * @param vo
     * @time: 2021/5/10 13:24
     * @author: Rock
     * @version 1.0
     */
    public Object getWxSign(GetWxSignReqVO vo) throws IOException {
        //url eg: https://api.new.iot08.com/bindInfo?openid=f13a9324bfa7417e8a3f768c&accessToken=537107cba577
        //从携带的 _url 中获取 在自己的数据库中的 account 表中的openid
        String openid = "";
        String[] urlArr = vo.getUrl().split("\\?");
        if (urlArr.length > 1) {
            urlArr = urlArr[1].split("&")[0].split("=");
            if (urlArr.length > 1) {
                openid = urlArr[1];
            }
        }
        if (StringUtil.isNotBlank(openid)) {
            Account account = accountService.findById(openid);
            if (account != null && StringUtil.isNotBlank(account.getWxgzMasterId())) {
                String appId = wxgzAppId;
                Wxgzconfig wxgzconfig = wxgzConfigService.findById(account.getWxgzMasterId());
                if (wxgzconfig != null && StringUtil.isNotBlank(wxgzconfig.getAppid())) {
                    appId = wxgzconfig.getAppid();
                }
                String ticket = weixinService.getTicket(account.getWxgzMasterId(), appId);
                String rstr = "sjdlsjldjsd";
                long timestamp = System.currentTimeMillis() / 1000;
                StringBuilder temp = new StringBuilder();
                temp.append("jsapi_ticket=").append(ticket).append("&noncestr=").append(rstr).append("&timestamp=")
                        .append(timestamp).append("&url=").append(vo.getUrl());
                String signature = CXUtil.byte2hex(CXUtil.getSHA1Digest(temp.toString()));
                JSONObject res = new JSONObject();
                res.put("signature", signature);
                res.put("nonceStr", rstr);
                res.put("timestamp", timestamp);
                res.put("appId", appId);
                log.info("getWxSign res = {}", res);
                return res;
            }
        }
        return "";
    }

    /**
     * @param vo
     * @time: 2021/5/14 15:51
     * @author: Rock
     * @version 1.0
     */
    public Object sendCode(SendCodeReqVO vo) {
        deviceService.sendAuthCode(vo.getImei());
        JSONObject res = new JSONObject();
        res.put("msg", "ok");
        return res;
    }
}
